//------------------------------------------------------------------------------
//  cameraentity.cc
//  (C) 2007 Radon Labs GmbH
//------------------------------------------------------------------------------
#include "stdneb.h"
#include "graphics/cameraentity.h"
#include "coregraphics/displaydevice.h"

namespace Graphics
{
ImplementClass(Graphics::CameraEntity, 'CMRE', Graphics::GraphicsEntity);

using namespace Math;
using namespace CoreGraphics;

//------------------------------------------------------------------------------
/**
*/
CameraEntity::CameraEntity() :
    viewProjDirty(true),
    angleOfView(50.0f),
    nearClipPlane(0.01f),
    farClipPlane(1000.0f)
{
    this->SetType(CameraType);
    float aspectRatio = DisplayDevice::Instance()->GetDisplayMode().GetAspectRatio();
    this->projMatrix = matrix44::perspfovrh(n_deg2rad(this->angleOfView), aspectRatio, this->nearClipPlane, this->farClipPlane);
    this->viewMatrix = matrix44::identity();
    this->viewProjMatrix = matrix44::identity();
}

//------------------------------------------------------------------------------
/**
*/
CameraEntity::~CameraEntity()
{
    // empty
}

//------------------------------------------------------------------------------
/**
    We need to keep track of modifications of the transformation matrix.
*/
void
CameraEntity::OnTransformChanged()
{
    this->viewProjDirty = true;
    this->viewMatrix = matrix44::inverse(this->GetTransform());
}

//------------------------------------------------------------------------------
/**
    Computes the clip status of a bounding box in global space against
    the view volume of this camera entity.
*/    
ClipStatus::Type
CameraEntity::ComputeClipStatus(const bbox& box)
{
    if (this->viewProjDirty)
    {
        this->UpdateViewProjMatrix();
    }
    ClipStatus::Type clipStatus = box.clipstatus(this->viewProjMatrix);
    return clipStatus;
}

//------------------------------------------------------------------------------
/**
    Updates the view-projection matrix.
*/
void
CameraEntity::UpdateViewProjMatrix()
{
    n_assert(this->viewProjDirty);
    this->viewProjDirty = false;
    this->viewProjMatrix = matrix44::multiply(this->viewMatrix, this->projMatrix);
}

//------------------------------------------------------------------------------
/**
    Updates the projection matrix.
*/
void
CameraEntity::UpdateProjMatrix()
{
    float aspectRatio = DisplayDevice::Instance()->GetDisplayMode().GetAspectRatio();
    matrix44 projM = matrix44::perspfovrh(n_deg2rad(this->angleOfView), aspectRatio, this->nearClipPlane, this->farClipPlane);
    this->SetProjTransform(projM);
}

//------------------------------------------------------------------------------
/**
*/
void 
CameraEntity::SetAngleOfView(float angle)
{
    if (this->angleOfView != angle)
    {
        this->angleOfView = angle;
        UpdateProjMatrix();
    }
}

//------------------------------------------------------------------------------
/**
*/
void 
CameraEntity::SetNearClipPlane(float nearPlane)
{
    if (this->nearClipPlane != nearPlane)
    {
        this->nearClipPlane = nearPlane;
        UpdateProjMatrix();
    }
}

//------------------------------------------------------------------------------
/**
*/
void 
CameraEntity::SetFarClipPlane(float farPlane)
{
    if (this->farClipPlane != farPlane)
    {
        this->farClipPlane = farPlane;
        UpdateProjMatrix();
    }
}

} // namespace Graphics
